package jscinttools.scint;
/* jhplot libraries */
import jhplot.PND;
import jhplot.P0I;
/* Aida libraries */
import hep.aida.ITupleColumn;
import hep.aida.ITupleFactory;
import hep.aida.ITuple;
import hep.aida.ITree;
import hep.aida.IDataPointSetFactory;
import hep.aida.IDataPointSet;
import hep.aida.IDataPoint;
import hep.aida.IMeasurement;
/* java libraries */
import java.lang.String;
import java.lang.StringBuilder;
import java.lang.System;
import java.lang.Double;
import java.io.InputStream;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.File;
import java.util.ArrayList;
/* jscinttools libraries */
import jscinttools.utilities.aidautilities.AidaFactories;

/**
 *  Class containing static methods t read formated data files
 *
 * @author     Marc-Antoine Verdier
 * @created    3 mars 2012
 */
public class DataFileReader{
	private DataFileReader(){}
	
	/**
	 *  Read an ASCII file containing data displayed in columns
	 *
	 * @param  file  	The full name (path + name + extension) of the file
	 * @return       	The DataContainer containing the data
	 */
	public static DataContainer readFileASCII(String file){
		return readFileASCII(file, "\t", "#", -1);
	}
	
	/**
	 *  Read an ASCII file containing data displayed in columns
	 *
	 * @param  file  	The full name (path + name + extension) of the file
	 * @param  colSep  	The character used to separate columns (default is "\t")
	 * @return       	The DataContainer containing the data
	 */
	public static DataContainer readFileASCII(String file, String colSep){
		return readFileASCII(file, colSep, "#", -1);
	}
	
	/**
	 *  Read an ASCII file containing data displayed in columns
	 *
	 * @param  file  	The full name (path + name + extension) of the file
	 * @param  colSep  	The character used to separate columns (default is "\t")
	 * @param  commentChar  The character used for comments. Lines starting with this character will be skiped (default is "#")
	 * @return       	The DataContainer containing the data
	 */
	public static DataContainer readFileASCII(String file, String colSep, String commentChar){
		return readFileASCII(file, colSep, commentChar, -1);
	}
	
	/**
	 *  Read an ASCII file containing data displayed in columns
	 *
	 * @param  file  	The full name (path + name + extension) of the file
	 * @param  colSep  	The character used to separate columns (default is "\t")
	 * @param  commentChar  The character used for comments. Lines starting with this character will be skiped (default is "#")
	 * @param  colTitleLine The line number to be used for column titles
	 * @return       	The DataContainer containing the data
	 */
	public static DataContainer readFileASCII(String file, String colSep, String commentChar, int colTitleLine){
		return new readFileASCIIImp(file, colSep, commentChar, colTitleLine);
	}
}


class readFileASCIIImp implements DataContainer{
	
	private final static String FS = File.separator;
	private int columns;
	private int rows;
	private int colTitleLine;
	private ITuple dataStr;
	private String[] colTitle;
	private ArrayList<ArrayList<String>> colDataStr;
	private String colSep;
	private String commChar;
	private String[] comments;
	private boolean firstLine;
	
	public readFileASCIIImp(String file, String colSep, String commChar, int colTitleLine){
		this.columns = 0;
		this.rows = 0;
		this.colSep = colSep;
		this.commChar = commChar;
		this.colTitle = null;
		this.colTitleLine = colTitleLine;
		this.colDataStr = new ArrayList<ArrayList<String>>();
		this.firstLine = true;
		readDataFile(file);
	}
	
	private void readDataFile(String file){
		try{
			InputStream ips = new FileInputStream(file);
			InputStreamReader ipsr = new InputStreamReader(ips);
			BufferedReader br = new BufferedReader(ipsr);
			String line;
			StringBuilder comBuild = new StringBuilder();
			System.out.println("\nReading File: " + file);
			int cnt = 0;
			while ((line = br.readLine()) != null){
				cnt++;
				if (cnt == colTitleLine)
					findColTitle(line);
				if (line.startsWith(commChar))
					comBuild.append(line);
				else if (cnt != colTitleLine && !line.startsWith(commChar))
					readLine(line);
			}
			fillStrTuple();
			String comm = comBuild.toString();
			this.comments = comm.split(colSep);
			System.out.println("\n... Done");
			br.close(); 
		}		
		catch (Exception e){
			System.out.println(e.toString());
		}
	}
	
	private void findColTitle(String line){
		this.colTitle = line.split(colSep);
		System.out.println("\nColumn Titles: ");
		for (int i = 0; i < colTitle.length; i++){
			System.out.println(colTitle[i].replace(" ", "_"));
		}
	}
			
	private void readLine(String line){
		try{
			String[] valStr = line.split(colSep);
			if (columns == 0)
				columns = valStr.length;
			if (firstLine)
				initColDataSrt(columns);
			for (int i = 0; i < columns; i++){
				colDataStr.get(i).add(valStr[i]);
			}
			rows++;
			firstLine = false;
		}
		catch (Exception e){
			System.out.println(e.toString());
		}
	}
	
	private void initColDataSrt(int columns){
		for (int i = 0; i < columns; i++){
			colDataStr.add(new ArrayList<String>());
		}
	}
	
	private void fillStrTuple(){
		String tupleColName = buildColTitle();
		this.dataStr = AidaFactories.TUPLE_FACTORY.create("tuple", "tuple", tupleColName);
		for (int i = 0; i < rows; i++){
			for (int j = 0; j < columns; j++){
				dataStr.fill(j, colDataStr.get(j).get(i));
			}
			dataStr.addRow();
		}
	}
	
	private String buildColTitle(){
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < columns; i++){
			if (colTitle != null && colTitle.length == columns)
				sb.append("string " + colTitle[i].replace(" ", "_"));
			else
				sb.append("string " + i);
			if (i != (columns - 1))
				sb.append(",");
		}
		return sb.toString();
	}
	
	public PND toPND(String name){
		PND data = new PND(name);
		for (int i = 0; i < rows; i++){
			double[] vals = new double[columns];
			for (int j = 0; j < columns; j++){
				vals[j] = Double.parseDouble(colDataStr.get(j).get(i));
			}
			data.add(vals);
		}
		return data;
	}
	
	public PND toPND(String name, int[] skipCol){
		PND data = new PND(name);
		int col = columns - skipCol.length;
		for (int i = 0; i < rows; i++){
			double[] vals = new double[col];
			for (int j = 0; j < columns; j++){
				if (testCol(j, skipCol))
					vals[j] = Double.parseDouble(colDataStr.get(j).get(i));
			}
			data.add(vals);
		}
		return data;
	}
	
	private boolean testCol(int index, int[] skipCol){
		boolean takeCol = true;
		for (int i = 0; i < skipCol.length; i++){
			if (index == skipCol[i])
				takeCol = false;
		}
		return takeCol;
	}
	
	public ITuple toTuple(String name){
		return toTuple(name, name, AidaFactories.TREE);
	}
	
	public ITuple toTuple(String path, String name, ITree tree){
		ITupleFactory tf = AidaFactories.ANALYSIS_FACTORY.createTupleFactory(tree);
		StringBuilder sb = new StringBuilder();
		for(int i = 0; i < columns; i++){
			if (colTitle != null && colTitle.length == columns)
				sb.append("double " + colTitle[i].replace(" ", "_"));
			else
				sb.append("double " + i);
			if (i != (columns - 1))
				sb.append(",");
		}
		ITuple tuple = tf.create(path, name, sb.toString());
		dataStr.start();
		tuple.start();
		while (dataStr.next()){
			for(int i = 0; i < columns; i++){
				ITupleColumn.String col = (ITupleColumn.String) dataStr.column(i);
				double val = Double.parseDouble(col.value());
				tuple.fill(i, val);
			}
			tuple.addRow();
		}
		return tuple;
	}
	
	public IDataPointSet toDPS(String name){
		return toDPS(name, name, AidaFactories.TREE);
	}
	
	public IDataPointSet toDPS(String path, String name, ITree tree){
		IDataPointSetFactory dpsf = AidaFactories.ANALYSIS_FACTORY.createDataPointSetFactory(tree);
		IDataPointSet dps = dpsf.create(path + FS + name, columns);
		dataStr.start();
		while (dataStr.next()){
			IDataPoint dp = dps.addPoint();
			for(int i = 0; i < columns; i++){
				IMeasurement m = dp.coordinate(i);
				ITupleColumn.String col = (ITupleColumn.String) dataStr.column(i);
				m.setValue(Double.parseDouble(col.value()));
			}
		}
		return dps;
	}
	
	public String[][] arrayString(){
		if (colTitle != null)
			return fillArrayTitle();
		else
			return fillArrayNoTitle();
	}
	
	private String[][] fillArrayTitle(){
		String[][] array = new String[columns][rows + 1];
		for (int i = 0; i < columns; i++){
			array[i][0] = colTitle[i];
		}
		for (int i = 0; i < rows; i++){
			for (int j = 0; j < columns; j++){
				array[j + 1][i + 1] = colDataStr.get(j).get(i);
			}
		}
		return array;
	}
	
	private String[][] fillArrayNoTitle(){
		String[][] array = new String[columns][rows];
		for (int i = 0; i < rows; i++){
			for (int j = 0; j < columns; j++){
				array[j][i] = colDataStr.get(j).get(i);
			}
		}
		return array;
	}
	
	public int columns(){
		return this.columns;
	}
	
	public int size(){
		return this.rows;	
	}
	
	public String[] comments(){
		return this.comments;
	}
}
